package org.joy.db2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 
 * @author Song Liu (lamfeeling2@gmail.com)
 */
public class Proximity {

    protected static Integer[] getProxArray2(Integer[] hits1, Integer[] hits2) {
	// find a group of nearest hit positions
	Integer[] res = new Integer[2];
	Arrays.fill(res, 0);
	int minDist = Integer.MAX_VALUE;
	for (int i = 0; i < hits1.length; i++) {
	    int t1 = (int) hits1[i];
	    int t2 = getProxArray2(t1, hits2);
	    if (t2 - t1 == 1) {
		// if the distance is 1, return this distance as the minimum
		// distance
		res[0] = t1;
		res[1] = t2;
		return res;
	    }
	    if (minDist > Math.abs(t1 - t2)) {
		minDist = Math.abs(t1 - t2);
		res[0] = t1;
		res[1] = t2;
	    }
	}
	return res;
    }

    protected static int getProxArray2(int pos, Integer[] hits2) {
	// find the nearest distance for given position
	int t[] = new int[hits2.length];
	for (int i = 0; i < hits2.length; i++) {
	    t[i] = hits2[i];
	}
	int res = -Arrays.binarySearch(t, pos);
	if (res <= 0) {
	    return pos;
	}
	if (res == 1) {
	    return hits2[0];
	}
	if (res == hits2.length + 1) {
	    return hits2[hits2.length - 1];
	}
	if (Math.abs(pos - hits2[res - 2]) < Math.abs(pos - hits2[res - 1])) {
	    return hits2[res - 2];
	} else {
	    return hits2[res - 1];
	}
    }

    // return the proximity measure of given hits
    public static int getProximity(List<Integer[]> hits) {
	ArrayList<Integer[]> lst = new ArrayList<Integer[]>();
	for (Integer[] e : hits) {
	    lst.add(e);
	}
	Integer[] res = compute(lst.toArray(new Integer[0][]));
	int dist = 1;
	for (int i = 1; i < res.length; i++) {
	    dist += res[i] - res[i - 1];
	}
	return dist;
    }

    // return min hits range in text
    public static Integer[] getMinRangeInText(List<Integer[]> hits) {
	ArrayList<Integer[]> lst = new ArrayList<Integer[]>();
	for (Integer[] pos : hits) {
	    // get positive positions
	    if (pos.length == 0) {
		// if no positive positions, return unavailable range
		return new Integer[] { -1, -1 };
	    }
	    lst.add(pos);
	}
	Integer[] res = compute(lst.toArray(new Integer[0][]));
	return new Integer[] { res[0], res[res.length - 1] };
    }

    public static Integer[] compute(Integer[][] hits) {
	if (hits.length == 0)
	    return new Integer[] { 0 };
	if (hits.length == 1) {
	    return new Integer[] { hits[0][0] };
	}
	Integer[] res = new Integer[hits.length];
	Integer[] init = getProxArray2(hits[0], hits[1]);
	res[0] = init[0];
	res[1] = init[1];
	for (int i = 2; i < hits.length; i++) {
	    res[i] = getProxArray2(res[i - 1], hits[i]);
	}
	Arrays.sort(res);
	return res;
    }
}
